{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Connections\n",
    "\n",
    "## Buffered Socket Connections\n",
    "\n",
    "`proxy.py` core provides buffered socket implementations.  In most of the cases, a buffered connection will be desired.  With buffered connections, we can queue data from our application code while leaving the responsibility of flushing the buffer on the core.\n",
    "\n",
    "One of the buffered connection class is `TcpServerConnection`, which manages connection to an upstream server.  Optionally, we can also enable encryption _(TLS)_ before communicating with the server.\n",
    "\n",
    "Import the following:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from proxy.core.connection import TcpServerConnection\n",
    "from proxy.common.utils import build_http_request\n",
    "from proxy.http.methods import httpMethods\n",
    "from proxy.http.parser import HttpParser, httpParserTypes\n",
    "\n",
    "request = build_http_request(\n",
    "    method=httpMethods.GET,\n",
    "    url=b'/',\n",
    "    headers={\n",
    "        b'Host': b'jaxl.com',\n",
    "    }\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's use `TcpServerConnection` to make a HTTP web server request."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "http_client = TcpServerConnection('jaxl.com', 80)\n",
    "http_client.connect()\n",
    "http_client.queue(memoryview(request))\n",
    "http_client.flush()\n",
    "\n",
    "http_response = HttpParser(httpParserTypes.RESPONSE_PARSER)\n",
    "while not http_response.is_complete:\n",
    "    http_response.parse(http_client.recv())\n",
    "http_client.close()\n",
    "\n",
    "print(http_response.build_response())\n",
    "\n",
    "assert http_response.is_complete\n",
    "assert http_response.code == b'301'\n",
    "assert http_response.reason == b'Moved Permanently'\n",
    "assert http_response.has_header(b'location')\n",
    "assert http_response.header(b'location') == b'https://jaxl.com/'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's use `TcpServerConnection` to make a HTTPS web server request."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "https_client = TcpServerConnection('jaxl.com', 443)\n",
    "https_client.connect()\n",
    "https_client.wrap(hostname='jaxl.com')\n",
    "\n",
    "https_client.queue(memoryview(request))\n",
    "https_client.flush()\n",
    "\n",
    "https_response = HttpParser(httpParserTypes.RESPONSE_PARSER)\n",
    "while not https_response.is_complete:\n",
    "    https_response.parse(https_client.recv())\n",
    "https_client.close()\n",
    "\n",
    "print(https_response.build_response())\n",
    "\n",
    "assert https_response.is_complete\n",
    "assert https_response.code == b'200'\n",
    "assert https_response.reason == b'OK'\n",
    "assert https_response.has_header(b'content-type')\n",
    "assert https_response.header(b'content-type') == b'text/html'"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "da9d6927d62b2b95bde149eedfbd5367cb7f465aad65a736f49c99ee3db39df7"
  },
  "kernelspec": {
   "display_name": "Python 3.10.0 64-bit ('venv310': venv)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.0"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
